home *** CD-ROM | disk | FTP | other *** search
- # include <ingres.h>
- # include <aux.h>
- # include <catalog.h>
- # include <symbol.h>
- # include <tree.h>
- # include "qrymod.h"
- # include <sccs.h>
- # include <errors.h>
-
- SCCSID(@(#)protect.c 8.4 4/15/85)
-
- /*
- ** PROTECT -- protection algorithm
- **
- ** This module performs the INGRES protection algorithm, as
- ** presented in Stonebraker & Rubinstein, "The INGRES Protection
- ** System", with a few modifications.
- **
- ** The basic algorithm is as follows:
- **
- ** The algorithm is applied once to each variable used in the
- ** query. Each variable has an initial check performed to
- ** determine applicability -- if the current user owns the
- ** relation, or if the relation is specially marked as being
- ** "all access to everyone", then the algorithm is skipped,
- ** thereby having effectively no restriction.
- **
- ** The set of all such variables is computed in 'protect',
- ** and then 'dopro' is called to process each of those. This
- ** is so the protection algorithm does not get applied recursively
- ** to constraints which define more than one variable. Notice
- ** that this could in itself be a protection violation, if it
- ** were acceptable to reference a relation you do not own in a
- ** PERMIT statement.
- **
- ** The effective query mode for this variable is then computed.
- ** This is the same as the query mode of the whole query if
- ** the variable in question is the result variable, otherwise
- ** it is "retrieve" mode.
- **
- ** The next step is to scan the query tree and create sets of
- ** domains referenced. Four sets are created:
- ** uset -- the set of domains updated (actually,
- ** referenced in the target list -- on a
- ** retrieve, this will be the set of domains
- ** retrieved to the user).
- ** rset -- the set of domains retrieved in some
- ** context other than the left hand side of
- ** an equal sign.
- ** aset -- the set of domains aggregated. This only
- ** includes domains aggregated with a simple
- ** aggregate (not an aggregate function) with
- ** no qualification, since it may be possible
- ** to come up with too much information other-
- ** wise.
- ** qset -- the set of domains retrieved for use in
- ** a qualification, but never stored. This
- ** includes domains in a qualification of an
- ** aggregate or aggregate function.
- ** For more details of domains in each of these sets, look at
- ** the routine 'makedset'.
- **
- ** If we had a retrieve operation in the first place, we will
- ** then merge 'uset' into 'rset' and clear 'uset', so that
- ** now 'uset' only contains domains which are actually updated,
- ** and 'rset' contains all domains which are retrieved.
- **
- ** Now that we know what is referenced, we can scan the protection
- ** catalog. We scan the entire catalog once for each variable
- ** mentioned in the query (except as already taken care of as
- ** described above).
- **
- ** We must create a set of all operations on this variable which
- ** are not yet resolved, that is, for which no PERMIT statements
- ** which qualify have been issued. We store this set in the
- ** variable "noperm". As PERMIT statements are found, bits will
- ** be cleared. If the variable is not zero by the end of the
- ** scan of the protection catalog, then we reject the query,
- ** saying that we don't have permission -- giving us default
- ** to deny.
- **
- ** For each tuple in the protection catalog for this relation,
- ** we call "proappl" to see if it applies to this query. This
- ** routine checks the user, terminal, time of day, and so forth
- ** (in fact, everything which is query-independent) and tells
- ** whether this tuple might apply.
- **
- ** If the tuple passes this initial check, we then do the query-
- ** dependent checking. This amounts to calling "prochk" once
- ** for each operation (and domain set) in the query. What we
- ** get back is a set of operations which this tuple applies to.
- ** If zero, the tuple doesn't apply at all; otherwise, it
- ** applies to at least one operation. If it applies to some-
- ** thing, we call it "interesting".
- **
- ** For "interesting" tuples, we now get the corresponding
- ** qualification (if one exists), and disjoin it to a set of
- ** protection constraints held in "pqual". Also, we mark
- ** any operations we found as having been done, by clearing
- ** bits in "noperm".
- **
- ** When we have completed scanning the protection catalog,
- ** we check "noperm". If it is non-zero, then we have some
- ** operation for which a PERMIT statement has not been issued,
- ** and we issue an error message. If this variable is ok,
- ** then we go on and try the next variable.
- **
- ** When all variables have been accounted for, we check to
- ** see if we have any qualifications collected from the
- ** protection algorithm. If so, we conjoin them to the
- ** query tree.
- **
- ** Finally, we return the root of the modified tree. This
- ** tree is guaranteed to have no authorization violations,
- ** and may be run as a regular query.
- **
- ** Parameters:
- ** root -- the root of the tree.
- **
- ** Returns:
- ** The root of the modified and authorized tree.
- **
- ** Side Effects:
- ** A possible non-local return on access violation.
- **
- ** Trace Flags:
- ** 50 - 59
- */
-
- int Proopmap[MAXPROQM + 1] =
- {
- PRO_RETR, /* 0 -- mdRETTERM */
- PRO_RETR, /* 1 -- mdRETR */
- PRO_APP, /* 2 -- mdAPP */
- PRO_REPL, /* 3 -- mdREPL */
- PRO_DEL, /* 4 -- mdDEL */
- };
-
- extern QTREE Prodes;
- extern char Terminal[];
- extern QTREE *gettree();
-
-
- QTREE *
- protect(root)
- QTREE *root;
- {
- register QTREE *r;
- register int i;
- register int vn;
- register DESC *d;
- int qmode;
- int varset;
-
- r = root;
-
- # ifdef xQTR1
- tTfp(50, -1, "\n->PROTECT\n\n");
- # endif
-
- varset = 0;
-
- /*
- ** Scan the range table and create a set of all variables
- ** which are 'interesting', that is, on which the protectin
- ** algorithm should be performed.
- */
-
- for (vn = 0; vn < MAXVAR + 1; vn++)
- {
- if (!Qt.qt_rangev[vn].rngvmark)
- continue;
- d = Qt.qt_rangev[vn].rngvdesc;
- if (d == NULL)
- syserr("null desc vn=%d", vn);
-
- /* if owner, accept any query */
- if (bequal(d->reldum.relowner, Usercode, UCODE_SZ))
- continue;
-
- /* check for "no restriction" bit asserted (= clear) */
- if (!bitset(S_PROTALL, d->reldum.relstat))
- continue;
- if (!bitset(S_PROTRET, d->reldum.relstat) &&
- (Qt.qt_qmode == mdRETR || Qt.qt_qmode == mdRET_UNI))
- continue;
-
- varset |= 1 << vn;
- }
-
- /*
- ** For each variable specified in varset (that is, for each
- ** variable in the initial query), do the real algorithm.
- */
-
- for (vn = 0; vn < MAXVAR + 1; vn++)
- {
- if ((varset & (1 << vn)) == 0)
- continue;
- d = Qt.qt_rangev[vn].rngvdesc;
-
- # ifdef xQTR1
- if (tTf(50, 1))
- printf("\nvn=%d: %.12s\n", vn, d->reldum.relid);
- # endif
-
- /*
- ** Determine the query mode for this variable. This
- ** is not the query mode of the original query,
- ** unless the variable is the result variable.
- */
-
- qmode = Qt.qt_qmode;
- if (vn != Qt.qt_resvar || qmode == mdRET_UNI)
- qmode = mdRETTERM;
-
- # ifdef xQTR3
- if (qmode == 1 || qmode > 4 || qmode < 0)
- syserr("protect: bad qmode %d", qmode);
- # endif
-
- /* do the interesting part of the algorithm */
- dopro(vn, r, qmode, NULL);
- }
-
- /* return the (authorized) tree */
- # ifdef xQTR1
- if (tTf(50, 15))
- treepr(r, "PROTECT->");
- # endif
- return (r);
- }
- /*
- ** DOPRO -- actually do the protection algorithm
- **
- ** This is the guts of it, broken off because it must be called
- ** recursively on aggregates. The algorithm is as discussed
- ** in the module header.
- **
- ** Parameters:
- ** varno -- the variable number of interest.
- ** root -- the root of the tree to modify.
- ** qmode -- the effective query mode for this relation.
- ** byset -- if non-NULL, a set of domains passed back
- ** which gets bound out of the aggregate func,
- ** in other words, the by list.
- **
- ** Returns:
- ** none
- **
- ** Side Effects:
- ** The tree pointed at by 'root' gets modified.
- ** Quite possibly 'Qt.qt_rangev' and 'Qt.qt_remap' get clobbered.
- **
- ** Called By:
- ** protect
- ** makedset -- on aggregates and aggregate functions.
- **
- ** Trace Flags:
- ** 51
- */
-
- dopro(varno, root, qmode, byset)
- int varno;
- QTREE *root;
- int qmode;
- int byset[8];
- {
- int qset[8];
- int uset[8];
- int aset[8];
- int rset[8];
- int zeros[8];
- QTREE *p;
- QTREE *pqual;
- register int i;
- register int vn;
- register QTREE *t;
- int noperm;
- int noqual;
- struct protect prokey, protup;
- struct tup_id lotid, hitid;
- struct qvect
- {
- QTREE *q_qual;
- int q_mode;
- };
- struct qvect quals[4];
- int j;
- extern QTREE *norml();
- extern QTREE *tree();
- extern QTREE *trimqlend();
-
-
- t = root;
- vn = varno;
-
- /* create domain usage sets */
- for (i = 0; i < 8; i++)
- {
- zeros[i] = uset[i] = rset[i] = qset[i] = aset[i] = 0;
- if (byset != NULL)
- byset[i] = 0;
- }
-
- /*
- ** Create domain usage set for target list side. There are
- ** two general cases: this is the root of the tree, or this
- ** is the head of an aggregate.
- */
-
- switch (t->sym.type)
- {
- case AGHEAD:
- /*
- ** An aggregate head falls into two classes: simple
- ** aggregate and aggregate function. In an aggregate
- ** function, care must be taken to bind the variables
- ** in the by-list outside of the aggregate. We use
- ** 'rset' as a temporary here.
- */
-
- if (t->left->sym.type == BYHEAD)
- {
- /* make by-list set */
- makedset(vn, t->left->left, NULL, rset, aset, qset);
-
- /* merge by-list set into qualification set */
- for (i = 0; i < 8; i++)
- {
- if (byset != NULL)
- byset[i] |= rset[i];
- qset[i] |= rset[i];
- rset[i] = 0;
- }
-
- /* make aggregate list set */
- makedset(vn, t->left->right->right, NULL, rset, aset, qset);
- }
- else
- {
- /* simple aggregate */
- # ifdef xQTR3
- if (t->left->sym.type != AOP)
- syserr("dopro: AGHEAD->left %d", t->left->sym.type);
- # endif
-
- /* check for qualification */
- if (t->right->sym.type == QLEND)
- {
- /* simple, unqualified aggregate */
- makedset(vn, t->left->right, NULL, aset, aset, qset);
- }
- else
- {
- # ifdef xQTR3
- if (t->right->sym.type != AND)
- syserr("dopro: AND=%d", t->right->sym.type);
- # endif
- makedset(vn, t->left->right, NULL, rset, aset, qset);
- }
- }
- break;
-
- case ROOT:
- makedset(vn, t->left, uset, rset, aset, qset);
- break;
- }
-
- /* scan qualification */
- makedset(vn, t->right, NULL, qset, aset, qset);
-
- /* if retrieval, drop the 'update' set */
- /* if delete or append, force an apparent update */
- switch (qmode)
- {
- case mdRETTERM:
- for (i = 0; i < 8; i++)
- uset[i] = 0;
- break;
-
- case mdDEL:
- case mdAPP:
- for (i = 0; i < 8; i++)
- uset[i] = -1;
- break;
- }
-
- # ifdef xQTR1
- if (tTf(51, 2))
- {
- printf("qmode %d\n", qmode);
- pr_set(uset, "uset");
- pr_set(rset, "rset");
- pr_set(aset, "aset");
- pr_set(qset, "qset");
- }
- # endif
-
- /* create a bit map of all referenced operations */
- noperm = 0;
- if (!bequal(uset, zeros, sizeof zeros))
- noperm |= Proopmap[qmode];
- if (!bequal(rset, zeros, sizeof zeros))
- noperm |= PRO_RETR;
- if (!bequal(aset, zeros, sizeof zeros))
- noperm |= PRO_AGGR;
- if (!bequal(qset, zeros, sizeof zeros))
- noperm |= PRO_TEST;
-
- /* if no operation, something is wrong */
- /* not nessasarily, consider a var that only occurs in an aggregate */
- /* if (noperm == 0)
- syserr("protect: no oper"); */
-
- /* initialize qualification portion */
- for (i = 0; i < 4; )
- quals[i++].q_qual = NULL;
- noqual = FALSE;
-
- /* check the protection catalog */
- opencatalog("protect", OR_READ);
- setkey(&Prodes, &prokey, Qt.qt_rangev[vn].rngvdesc->reldum.relid, PRORELID);
- setkey(&Prodes, &prokey, Qt.qt_rangev[vn].rngvdesc->reldum.relowner, PRORELOWN);
- find(&Prodes, EXACTKEY, &lotid, &hitid, &prokey);
-
- while ((i = get(&Prodes, &lotid, &hitid, &protup, TRUE)) == 0)
- {
- if (kcompare(&Prodes, &prokey, &protup) != 0)
- continue;
-
- # ifdef xQTR2
- if (tTf(51, 4))
- {
- printf("PROTECT: ");
- printup(&Prodes, &protup);
- }
- # endif
-
- /* check if this is the correct user, terminal, etc */
- if (!proappl(&protup))
- continue;
-
- /* alright, let's check the operation */
- i = 0;
- if (qmode != mdRETTERM)
- i = quals[0].q_mode = prochk(Proopmap[qmode], uset, &protup);
- i |= quals[1].q_mode = prochk(PRO_RETR, rset, &protup);
- i |= quals[2].q_mode = prochk(PRO_AGGR, aset, &protup);
- i |= quals[3].q_mode = prochk(PRO_TEST, qset, &protup);
-
- # ifdef xQTR2
- if (tTf(51, 5))
- printf("Satisfies operations %o\n", i);
- # endif
-
- /* see if this tuple is "interesting" */
- if (i == 0)
- continue;
-
- /* it is! get the qualification (if any) */
- if (protup.protree >= 0)
- {
- p = gettree(Qt.qt_rangev[vn].rngvdesc->reldum.relid,
- Qt.qt_rangev[vn].rngvdesc->reldum.relowner,
- mdPROT, protup.protree, FALSE);
- # ifdef xQTR2
- if (tTf(51, 6))
- treepr(p, "Protection Clause");
- # endif
- p = trimqlend(p->right);
- # ifdef xQTR3
- /* check for a non-null qualification */
- if (p == NULL)
- syserr("protect: null tree");
- # endif
-
- /* translate to the interesting variable */
- j = protup.proresvar;
- if (Qt.qt_remap[j] >= 0)
- j = Qt.qt_remap[j];
- mergevar(j, varno, p);
-
- /* disjoin the protection qual to real qual */
- for (j = 0; j < 4; j++)
- {
- if (quals[j].q_mode == 0)
- continue;
- if (quals[j].q_qual == NULL)
- quals[j].q_qual = p;
- else
- quals[j].q_qual = tree(quals[j].q_qual, p, OR, 0);
- }
- }
- else
- noqual = TRUE;
-
- /* mark this operation as having been handled */
- noperm &= ~i;
- }
-
- /* test 'get' return code */
- if (i < 0)
- syserr("protect: get");
-
- # ifdef xQTR1
- if (tTf(51, 12))
- printf("No perm on %o\n", noperm);
- # endif
-
- /* see if no tuples applied for some operation */
- if (noperm != 0)
- qmerror(PVIOL, Qt.qt_qmode, vn, 0);
-
- /* see if we want to modify the query at all */
- if (!noqual)
- {
- /* conjoin the qualification */
- pqual = NULL;
- for (i = 0; i < 4; i++)
- if (quals[i].q_qual != NULL)
- if (pqual == NULL)
- pqual = quals[i].q_qual;
- else
- pqual = tree(pqual, quals[i].q_qual, AND, 0);
- pqual = tree(pqual, tree(NULL, NULL, QLEND, 0), AND, 0);
- appqual(pqual, t);
-
- /* normalize the tree */
- t->right = norml(trimqlend(t->right));
- }
- }
- /*
- ** MAKEDSET -- make domain reference sets
- **
- ** This routine creates some sets which reflect the usage of
- ** domains for a particular variable.
- **
- ** The interesting nodes are 'case' labels in the large
- ** switch statement which comprises most of the code. To
- ** describe briefly:
- **
- ** VAR nodes are easy: if they are for the current variable,
- ** set the bit corresponding to the domain in the
- ** 'retrieval' set. They can have no descendents,
- ** so just return.
- ** RESDOM nodes are also easy: they can be handled the same,
- ** but the bit is set in the 'update' set instead.
- ** AGHEAD nodes signal the beginning of an aggregate or
- ** aggregate function. In this case, we scan the
- ** qualification first (noting that RESDOM and VAR
- ** nodes are processed as 'qualification' sets
- ** instead of 'retrieval' or 'update' sets). Then,
- ** if the aggregate has a WHERE clause or a BY list,
- ** we treat it as a retrieve; otherwise, we call our-
- ** selves recursively treating VAR nodes as 'aggregate'
- ** types rather than 'retrieve' types.
- ** BYHEAD nodes signal the beginning of a BY list. The left
- ** subtree (the actual BY-list) is processed with
- ** RESDOM nodes ignored (since they are pseudo-domains
- ** anyhow) and VAR nodes mapped into the 'qualification'
- ** set. Then we check the right subtree (which better
- ** begin with an AOP node!) and continue processing.
- ** AOP nodes must have a null left subtree, so we just drop
- ** to the right subtree and iterate. Notice that we
- ** do NOT map VAR nodes into the 'aggregate' set for
- ** this node, since this has already been done by the
- ** AGHEAD node; also, this aggregate might be counted
- ** as a retrieve operation instead of an aggregate
- ** operation (as far as the protection system is con-
- ** cerned) -- this has been handled by the AGHEAD
- ** node.
- ** All other nodes are processed recursively along both edges.
- **
- ** Parameters:
- ** vn -- the variable number that we are currently
- ** interested in.
- ** tree -- the root of the tree to scan. Notice that this
- ** will in general be only one half of the tree --
- ** makedset will be called once for the target
- ** list and once for the qualification, with
- ** different sets for the following parameters.
- ** uset -- adjusted to be the set of all domains
- ** updated.
- ** rset -- adjusted to be the set of all domains
- ** retrieved implicitly, that is, on the right-
- ** hand-side of an assignment operator.
- ** aset -- adjusted to be the set of all domains
- ** aggregated. Notice that this set is not
- ** adjusted explicitly, but rather is passed
- ** to recursive incarnations of this routine
- ** as 'rset'.
- ** qset -- adjusted to be the set of domains retrieved
- ** implicitly in a qualification. Like 'aset',
- ** this is passed as 'rset' to recursive
- ** incarnations.
- **
- ** Returns:
- ** none
- **
- ** Side Effects:
- ** none
- **
- ** Called By:
- ** protect() -- in two places.
- **
- ** Trace Flags:
- ** 53
- **
- */
-
- makedset(vn, tree, uset, rset, aset, qset)
- int vn;
- QTREE *tree;
- int uset[8];
- int rset[8];
- int aset[8];
- int qset[8];
- {
- register QTREE *t;
- register int i;
- int byset[8];
-
- t = tree;
-
- # ifdef xQTR1
- if (tTf(53, 0))
- {
- printf("->makedset\n");
- pr_set(uset, "uset");
- pr_set(rset, "rset");
- pr_set(aset, "aset");
- pr_set(qset, "qset");
- }
- # endif
-
- while (t != NULL)
- {
- switch (t->sym.type)
- {
- case VAR:
- if (t->sym.value.sym_var.varno == vn)
- lsetbit(t->sym.value.sym_var.attno, rset);
- break;
-
- case AGHEAD:
- /* do protection on qualification */
- dopro(vn, t, -1, byset);
-
- /* merge by-list set into qualification set */
- for (i = 0; i < 8; i++)
- qset[i] |= byset[i];
-
- break;
-
- case BYHEAD:
- case AOP:
- syserr("makedset: node %d", t->sym.type);
-
- case RESDOM:
- if (t->sym.value.sym_resdom.resno == 0)
- {
- /* tid -- ignore right subtree (and this node) */
- t = t->left;
- continue;
- }
- if (uset != NULL)
- lsetbit(t->sym.value.sym_resdom.resno, uset);
- /* explicit fall-through to "default" case */
-
- default:
- /* handle left subtree (recursively) */
- makedset(vn, t->left, uset, rset, aset, qset);
-
- /* handle right subtree (iteratively) */
- t = t->right;
- continue;
- }
- break;
- }
-
- # ifdef xQTR1
- if (tTf(53, 15))
- {
- printf("makedset->\n");
- pr_set(uset, "uset");
- pr_set(rset, "rset");
- pr_set(aset, "aset");
- pr_set(qset, "qset");
- }
- # endif
-
- return;
- }
- /*
- ** PROAPPL -- check for protection tuple applicable
- **
- ** A given protection catalog tuple is checked in a query-
- ** independent way for applicability.
- **
- ** This routine checks such environmental constraints as the
- ** user, the terminal, and the time of day. The code is
- ** fairly straightforward, just take a look.
- **
- ** One note: the user and terminal codes contained in the
- ** protection catalog are blank to mean 'any value' of the
- ** corresponding field.
- **
- ** Parameters:
- ** protup -- the protection tuple to compare against.
- **
- ** Returns:
- ** TRUE -- this tuple applies to the current environment.
- ** FALSE -- this tuple does not apply.
- **
- ** Side Effects:
- ** none (unless you include trashing the static vector
- ** returned by localtime).
- **
- ** Called By:
- ** protect()
- **
- ** Trace Flags:
- ** 54
- */
-
- proappl(protup)
- struct protect *protup;
- {
- register struct protect *p;
- int tvect[2];
- register int *tt;
- extern int *localtime();
- register int mtime;
-
- p = protup;
-
- /* check for correct user [insert clique code here] */
- if (!bequal(" ", p->prouser, 2))
- {
- if (!bequal(p->prouser, Usercode, UCODE_SZ))
- {
- # ifdef xQTR2
- if (tTf(54, 0))
- printf(" ~user\n");
- # endif
- return (FALSE);
- }
- }
-
- /* check for correct terminal */
- if (p->proterm[0] != ' ')
- {
- if (!sequal(p->proterm, Terminal))
- {
- # ifdef xQTR2
- if (tTf(54, 0))
- printf(" ~term\n");
- # endif
- return (FALSE);
- }
- }
-
- /* check for correct time of day & week */
- time(tvect);
- tt = localtime(tvect);
- mtime = tt[2] * 60 + tt[1];
-
- if (p->protodbgn > mtime || p->protodend < mtime)
- {
- # ifdef xQTR2
- if (tTf(54, 0))
- printf(" ~tod\n");
- # endif
- return (FALSE);
- }
- if (p->prodowbgn > tt[6] || p->prodowend < tt[6])
- {
- # ifdef xQTR2
- if (tTf(54, 0))
- printf(" ~dow\n");
- # endif
- return (FALSE);
- }
-
- /* hasn't failed yet -- I guess it's ok */
- return (TRUE);
- }
- /*
- ** PROCHK -- query-dependent protection tuple check
- **
- ** This routine does the query-dependent part of checking
- ** the validity of a protection tuple. Unlike proappl,
- ** which looked at aspects of the environment but not the
- ** query being run, this routine assumes that the environ-
- ** ment is ok, and checks that if it applies to this tuple.
- **
- ** Two things are checked. The first is if this tuple applies
- ** to the operation in question (passed as 'inbit'). The
- ** second is if the set of domains in the tuple contains the
- ** set of domains in the query. If either of these fail,
- ** the return is zero. Otherwise the return is the operation
- ** bit. In otherwise, the return is the operation to which
- ** this tuple applies (if any).
- **
- ** As a special check, the domain set is checked for all
- ** zero. If so, no domains have been referenced for this
- ** operation at all, and we return zero. In other words, this
- ** tuple might apply to this operation, but since we don't
- ** use the operation anyhow we will ignore it. It is important
- ** to handle things in this way so that the qualification for
- ** this tuple doesn't get appended if the variable is not
- ** used in a particular context.
- **
- ** Parameters:
- ** inbit -- the bit describing the operation to be
- ** checked. Note that only one bit should
- ** be set in this word, although this is
- ** not checked.
- ** domset -- the set of domains actually referenced
- ** in this query for the operation described
- ** by 'inbit'.
- ** protup -- the tuple in question.
- **
- ** Returns:
- ** The operation (if any) to which this tuple applies.
- **
- ** Side Effects:
- ** none
- **
- ** Called By:
- ** protect() -- in four places.
- **
- ** Trace Flags:
- ** 55
- */
-
- prochk(inbit, domset, protup)
- int inbit;
- int domset[8];
- struct protect *protup;
- {
- register struct protect *p;
- register int *d;
- register int i;
-
- p = protup;
- d = domset;
-
- # ifdef xQTR1
- if (tTf(55, 0))
- {
- printf("->prochk, inbit=%o, proopset=%o\n", inbit, p->proopset);
- pr_set(d, "domset");
- pr_set(p->prodomset, "prodomset");
- }
- # endif
-
- /* check for null domain set, if so return zero */
- for (i = 0; i < 8; i++)
- if (d[i] != 0)
- break;
- if (i >= 8)
- {
- # ifdef xQTR2
- tTfp(55, 15, "prochk-> null set\n");
- # endif
- return (0);
- }
-
- /* see if this tuple applies to this operation */
- if ((inbit & p->proopset) == 0)
- {
- # ifdef xQTR2
- tTfp(55, 15, "prochk-> no op\n");
- # endif
- return (0);
- }
-
- /* check if domains are a subset */
- for (i = 0; i < 8; i++)
- {
- if ((d[i] & ~p->prodomset[i]) != 0)
- {
- /* failure */
- # ifdef xQTR2
- tTfp(55, 15, "prochk-> not subset\n");
- # endif
- return (0);
- }
- }
-
- /* this is hereby an "interesting" tuple */
- # ifdef xQTR2
- if (tTf(55, 15))
- printf("prochk-> %d\n", inbit);
- # endif
- return (inbit);
- }
-
- # ifdef xQTR1
-
- /*
- ** PR_SET -- print set for debugging
- **
- ** This routine prints a 128-bit set for debugging.
- **
- ** Parameters:
- ** xset -- the set to convert.
- ** labl -- a label to print before the set.
- **
- ** Returns:
- ** a pointer to the converted string.
- **
- ** Side Effects:
- ** none
- */
-
- pr_set(xset, labl)
- short xset[8];
- char *labl;
- {
- register short *x;
- register int i;
- register long *y;
-
- printf("\t%s: ", labl);
- x = xset;
- y = (long *) x;
- if (x == NULL)
- {
- printf("<NULL>\n");
- return;
- }
- for (i = 7; i >= 0; i--)
- printf("%x/", x[i]);
- printf(" <> ");
- for (i = 0; i < 4; i++)
- printf("/%ld", y[i]);
- printf("\n");
- }
-
- # endif
-